﻿using DataTurnClient.Interface;
using DataTurnClient.Model;
using DataTurnClient.Server;
using DynamicData;
using Newtonsoft.Json;
using ReactiveUI;
using Splat;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Reactive.Concurrency;
using System.Reflection.Emit;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Threading;
using System.Xml.Linq;
using Windows.UI.Xaml;
using static System.Net.Mime.MediaTypeNames;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Tab;

namespace DataTurnClient.ViewModel
{
    public class MainTurnViewModel : ReactiveObject
    {
        public ViewModelActivator Activator { get; }

        public IScheduler MainScheduler;


        #region 绑定视图
        /// <summary>
        /// 任务列表
        /// </summary>
        public BindingList<Job> JobList { get; set; } = new BindingList<Job>();
        /// <summary>
        /// 日志列表
        /// </summary>
        public BindingList<Log> LogList { get; set; } = new BindingList<Log>();

        /// <summary>
        /// 设置列表
        /// </summary>
        public List<Setting> SetList { get; set; } = new List<Setting>();

        public List<RouteLine> RouteList { get; set; } = new List<RouteLine>();

        #endregion

        #region 页面属性


        public bool IsTimer
        {
            get => _IsTimer;
            set => this.RaiseAndSetIfChanged(ref _IsTimer, value);
        }
        private bool _IsTimer;

        /// <summary>
        /// 当前时间
        /// </summary>
        public List<string> NewTime
        {
            get => DateTime.Now.ToString("HH-mm-ss").Split('-').ToList();
        }

        public string JobTimeString
        {
            get => _JobTimeString;
            set =>  this.RaiseAndSetIfChanged(ref _JobTimeString, value); 
        }
        private string _JobTimeString;

        public Job CreateJob
        {
            get => _CreateJob;
            set => this.RaiseAndSetIfChanged(ref _CreateJob, value);
        }
        private Job _CreateJob = new Job();
        #endregion

        #region Command方法
        /// <summary>
        /// 查询任务
        /// </summary>
        public ReactiveCommand<Unit, Unit> SelectJobCommand { get; }

        /// <summary>
        /// 查询设置，包括填充默认数据
        /// </summary>
        public ReactiveCommand<Unit, Unit> SelectSetCommand { get; }

        /// <summary>
        /// 单次运行任务
        /// </summary>
        public ReactiveCommand<string, Unit> RunJobCommand { get; }

        /// <summary>
        /// 运行所有正常状态的任务
        /// </summary>
        public ReactiveCommand<Unit, Unit> RunAllJobCommand { get; }

        /// <summary>
        /// 更改任务状态
        /// </summary>
        public ReactiveCommand<string, Unit> ChangeJobStatusCommand { get; }

        /// <summary>
        /// 定时器检查符合时间条件的任务，并运行
        /// </summary>
        public ReactiveCommand<Unit, Unit> IsRunTimeCommand { get; }

        /// <summary>
        /// 清除日志视图
        /// </summary>
        public ReactiveCommand<Unit, Unit> ClearLogGridCommand { get; }


        /// <summary>
        /// 显示任务详情
        /// </summary>
        public ReactiveCommand<int, string> ShowJobMessageCommand { get; }

        /// <summary>
        /// 显示日志详情
        /// </summary>
        public ReactiveCommand<int, string> ShowLogMessageCommand { get; }

        /// <summary>
        /// 添加日志
        /// </summary>
        public ReactiveCommand<LogRead, Unit> AddLogCommand { get; }

        /// <summary>
        /// 添加任务
        /// </summary>
        public ReactiveCommand<Job, Result<int>> AddJobCommand { get; }

        /// <summary>
        /// 更新任务
        /// </summary>
        public ReactiveCommand<Job, Result<int>> UpdateJobCommand { get; }

        /// <summary>
        /// 根据任务名返回一个符合的任务
        /// </summary>
        public ReactiveCommand<string, Result<Job>> SelectOneJobCommand { get; }

        /// <summary>
        /// 初始化，同步表结构，填充数据
        /// </summary>
        public ReactiveCommand<Unit, Result<string>> ReloadTableCommand { get; }

        /// <summary>
        /// 删除任务
        /// </summary>
        public ReactiveCommand<Job, Result<int>> DeleteJobCommand { get; }

        #endregion

        public List<Setting> BackUpSetting { get; set; } = new List<Setting>() 
        {
            new Setting()
            {
                Id = 1,
                SetGroup = "Base",
                SetName = "Timer",
                SetValue = "60000",
                SetDetail = "设置定时器"
            },
            new Setting()
            {
                Id = 2,
                SetGroup = "Base",
                SetName = "Log",
                SetValue = "100",
                SetDetail = "日志界面最大条数"
            },
            new Setting()
            {
                Id = 3,
                SetGroup = "Base",
                SetName = "Run",
                SetValue = "1",
                SetDetail = "是否默认打开即计时"
            },
            new Setting()
            {
                Id = 4,
                SetGroup = "DingSet",
                SetName = "On",
                SetValue = "0",
                SetDetail = "是否打开钉钉通知"

            },
            new Setting()
            {
                Id = 5,
                SetGroup = "DingSet",
                SetName = "Url",
                SetValue = "",
                SetDetail = "钉钉机器人链接"

            },
            new Setting()
            {
                Id = 6,
                SetGroup = "DingSet",
                SetName = "SafeCode",
                SetValue = "",
                SetDetail = "钉钉机器人设置的安全口令"

            },
        };



        //查询任务

        public MainTurnViewModel(IScheduler mainScheduler)
        {
            MainScheduler = mainScheduler;
            Locator.CurrentMutable.RegisterLazySingleton(() => new MainTurnViewModel(mainScheduler));
            Activator = new ViewModelActivator();
            SelectJobCommand = ReactiveCommand.Create(SelectJobCommandImpl);
            SelectSetCommand = ReactiveCommand.Create(SelectSetCommandImpl);
            RunJobCommand = ReactiveCommand.Create<string>(RunJobCommandImpl);
            RunAllJobCommand = ReactiveCommand.Create(RunAllJobCommandImpl);
            ChangeJobStatusCommand = ReactiveCommand.Create<string>(ChangeJobStatusCommandImpl);
            IsRunTimeCommand = ReactiveCommand.Create(IsRunTimeCommandImpl);
            ClearLogGridCommand = ReactiveCommand.Create(ClearLogGridCommandImpl);
            ShowJobMessageCommand = ReactiveCommand.Create<int, string>(ShowJobMessageCommandImpl);
            ShowLogMessageCommand = ReactiveCommand.Create<int, string>(ShowLogMessageCommandImpl);
            AddLogCommand = ReactiveCommand.Create<LogRead>(AddLogCommandImpl);
            AddJobCommand = ReactiveCommand.Create<Job, Result<int>>(AddJobCommandImpl);
            UpdateJobCommand = ReactiveCommand.Create<Job, Result<int>>(UpdateJobCommandImpl);
            SelectOneJobCommand = ReactiveCommand.Create<string, Result<Job>>(SelectOneJobCommandImpl);
            ReloadTableCommand = ReactiveCommand.Create(ReloadTableCommandImpl);
            DeleteJobCommand = ReactiveCommand.Create<Job, Result<int>>(DeleteJobCommandImpl);
        }

        private void SelectJobCommandImpl()
        {
            try
            {
                var service = Locator.Current.GetService<IDBHelperService>();
                using (var db = service.SqlSugarClient(Globals.DbConnect, Globals.DbType))
                {
                    var DbJobList = db.Queryable<Job>().ToList();
                    if (DbJobList != null && DbJobList.Count > 0)
                    {
                        if (JobList.Count > DbJobList.Count)
                        {
                            JobList.Clear();
                        }
                        foreach (var jobItem in DbJobList)
                        {
                            var isJob = JobList.Where(x => x.JobCode == jobItem.JobCode).FirstOrDefault();
                            if (isJob == null)
                            {
                                jobItem.JobRunStatus = Job.JobRunType.Wating;
                                JobList.Add(jobItem);
                            }
                            else
                            {
                                isJob.JobRunStatus = isJob.JobRunStatus == Job.JobRunType.Run ? Job.JobRunType.Run : Job.JobRunType.Wating;
                                isJob.JobName = jobItem.JobName;
                                isJob.JobStatus = jobItem.JobStatus;
                                isJob.JobRunTime = jobItem.JobRunTime;
                                isJob.JobWeek = jobItem.JobWeek;
                                isJob.JobRoute = jobItem.JobRoute;
                                isJob.JobDetail = jobItem.JobDetail;
                                isJob.JobMode = jobItem.JobMode;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                AddLogCommandImpl( new LogRead() { ModelName = "SelectJobCommandImpl", ModelContent = ex.Message });
            }
        }

        private void SelectSetCommandImpl()
        {
            try
            {
                var tool = Locator.Current.GetService<ITool>();
                var service = Locator.Current.GetService<IDBHelperService>();
                using (var db = service.SqlSugarClient(Globals.DbConnect, Globals.DbType))
                {
                    var Setting = db.Queryable<Setting>().ToList();
                    if (Setting.Count > SetList.Count)
                    {
                        SetList.Clear();
                    }
                    SetList = Setting;
                    foreach (var item in Setting)
                    {
                        var Set = SetList.Where(x => x.SetName == item.SetName).ToList().FirstOrDefault();
                        if (Set == null)
                        {
                            SetList.Add(item);
                        }
                    }
                    foreach (var item in Setting)
                    {
                        var Set = SetList.Where(x => x.SetName == item.SetName).ToList().FirstOrDefault();

                        if (Set.SetName == "Timer")
                        {
                            Globals.Base_Timer = Convert.ToInt32(Set.SetValue);
                        }
                        if (Set.SetName == "Log")
                        {
                            Globals.Base_Log = Convert.ToInt32(Set.SetValue);
                        }
                        if (Set.SetName == "Run")
                        {
                            Globals.Base_Run = Convert.ToInt32(Set.SetValue);
                            IsTimer = Convert.ToInt32(Set.SetValue) > 0 ? true:false;
                        }
                        if (Set.SetName == "On")
                        {
                            Globals.DingSet_On = Convert.ToInt32(Set.SetValue);
                        }
                        if (Set.SetName == "Url")
                        {
                            Globals.DingSet_Url = Set.SetValue;
                        }
                        if (Set.SetName == "SafeCode")
                        {
                            Globals.DingSet_SafeCode = Set.SetValue;
                        }
                        Set.SetGroup = item.SetGroup;
                        Set.SetValue = item.SetValue;
                        Set.SetDetail = item.SetDetail;
                    }
                    var Route = db.Queryable<RouteLine>().ToList();
                    if (Route.Count > RouteList.Count)
                    {
                        RouteList.Clear();
                    }
                    Globals.RouteList = Route;
                    foreach (var route in Route)
                    {
                        var Set = RouteList.Where(x => x.Id == route.Id).ToList().FirstOrDefault();
                        if (Set == null)
                        {
                            RouteList.Add(route);
                        }
                        else
                        {
                            Set.Ip = route.Ip;
                            Set.Port = route.Port;
                            Set.Path = route.Path;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                AddLogCommandImpl(new LogRead() { ModelName = "SelectSetCommandImpl", ModelContent = ex.Message });
            }
        }

        private Result<string> ReloadTableCommandImpl()
        {
            Result<string> result = new Result<string>()
            {
                Code = 200,
                Success = true,
                Message = "初始化成功"
            };
            try
            {
                var service = Locator.Current.GetService<IDBHelperService>();
                using (var db = service.SqlSugarClient(Globals.DbConnect, Globals.DbType))
                {
                    service.DataCodeCopy<Job>(db);
                    service.DataCodeCopy<RouteLine>(db);
                    service.DataCodeCopy<Setting>(db);
                    var Setting = db.Queryable<Setting>().ToList();
                    if (Setting == null || Setting.Count == 0)
                    {
                        db.Insertable(BackUpSetting).ExecuteCommand();
                    }
                }
            }
            catch (Exception ex)
            {
                result.Code = 500;
                result.Success = false;
                result.Message = ex.Message;
            }
            return result;
        }

        private void RunJobCommandImpl(string JobCode)
        {
            var server = Locator.Current.GetService<ITool>();
            var job = JobList.Where(x => x.JobCode == JobCode).FirstOrDefault();
            AddLogCommandImpl(new LogRead() { ModelName = "RunJobCommandImpl", ModelContent = $"执行任务{JobCode}" });
            job.JobRunStatus = Job.JobRunType.Run;
            Func<List<Job>, List<RouteLine>, string, Result<string>> myFunc = new Func<List<Job>, List<RouteLine>, string, Result<string>>(server.Execute);
            AsyncCallback myCallBack = GetResult;
            myFunc.BeginInvoke(JobList.ToList(), RouteList.ToList(), job.JobCode, myCallBack, myFunc);            
        }

        private void RunAllJobCommandImpl()
        {
            var logserver = Locator.Current.GetService<ITool>();
            logserver.WriterText("head ", DateTime.Now.ToString("HH-mm-ss") + "      所有任务运行");
            AddLogCommandImpl(new LogRead() { ModelName = "RunAllJobCommandImpl", ModelContent = $"点击运行所有任务" });
            var job = JobList.Where(x => x.JobStatus == 1 && x.JobRunStatus != Job.JobRunType.Run).ToList();
            if (job.Count > 0)
            {
                foreach (var jobs in job)
                {
                    RunJobCommandImpl(jobs.JobCode);
                }
            }
            else
            {
                //AddLog("任务列表为空");
            }
        }

        private void ChangeJobStatusCommandImpl(string JobCode)
        {
            var job = JobList.Where(x => x.JobCode == JobCode).FirstOrDefault();
            int isRun = job.JobStatus == 0 ? 1 : 0;
            var server = Locator.Current.GetService<IDBHelperService>();
            var log = Locator.Current.GetService<ITool>();
            using (var db = server.SqlSugarClient(Globals.DbConnect, Globals.DbType))
            {
                var results = db.Updateable<Job>()
                                            .SetColumns(it =>  new Job() {  JobStatus = isRun } )
                                            .Where(it => it.JobCode == job.JobCode).ExecuteCommand();
                job.JobStatus = results == 1 ? isRun : job.JobStatus;
                AddLogCommandImpl(new LogRead() { ModelName = "ChangeJobStatusCommandImpl", ModelContent = $"{JobCode} 更改运行状态为：{job.JobStatus}" });
            }
            var logserver = Locator.Current.GetService<ITool>();
            logserver.WriterText("update ", DateTime.Now.ToString("HH-mm-ss") + "  " + JsonConvert.SerializeObject(job));
        }

        private void IsRunTimeCommandImpl()
        {
            if (IsTimer)
            {
                var job = JobList.Where(x => x.JobStatus == 1).ToList();
                if (job.Count > 0)
                {
                    var service = Locator.Current.GetService<ITool>();
                    foreach (var jobs in job)
                    {
                        if (service.IsTime(jobs.Times, NewTime) && service.IsWeek(jobs.JobWeek))
                        {
                            var server = Locator.Current.GetService<ITool>();
                            RunJobCommandImpl(jobs.JobCode);
                            server.WriterText("Time ", DateTime.Now.ToString("HH-mm-ss") + "      " + JsonConvert.SerializeObject(jobs));
                        }
                    }
                }
                else
                {
                    //AddLog("任务列表为空");
                }
            }
        }

        private void ClearLogGridCommandImpl()
        {
            LogList.Clear();
        }

        private string ShowJobMessageCommandImpl(int index)
        {
            var server = Locator.Current.GetService<ITool>();
            var job = JobList[index];
            return server.MsgShow(job);
        }

        private string ShowLogMessageCommandImpl(int index)
        {
            var server = Locator.Current.GetService<ITool>();
            var log = LogList[index];
            return server.LogShow(log);
        }

        private void GetResult(IAsyncResult ar)
        {
            Func<List<Job>, List<RouteLine>, string, Result<string>> func = (Func<List<Job>, List<RouteLine>, string, Result<string>>)ar.AsyncState;
            Result<string> ss = func.EndInvoke(ar);
            Console.WriteLine(JsonConvert.SerializeObject(ss));
            MainScheduler.Schedule(() =>
            {
                AddLogCommandImpl(new LogRead() { ModelName = "GetResult", ModelContent = JsonConvert.SerializeObject(ss) });
            });
        }

        private void AddLogCommandImpl(LogRead read)
        {
            Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
            Task.Run(() =>
            {
                dispatcher.Invoke(new Action(() =>
                {
                    try
                    {
                        if (SetList == null)
                        {
                            SetList = new List<Setting>();
                        }
                        if (SetList.Count == 0)
                        {
                            SelectSetCommand.Execute().Subscribe();
                        }
                        Log logs = new Log();
                        logs.HappenTime = DateTime.Now.ToString("MM-dd HH:mm:ss");
                        logs.HappenModel = read.ModelName;
                        logs.HappenDtal = read.ModelContent;
                        LogList.Add(logs);
                        int logCount = Convert.ToInt32(SetList.Where(x => x.SetName == "Log").FirstOrDefault().SetValue);
                        AddLogLocalHostCommandImpl(read);

                        if (LogList.Count > Globals.Base_Log)
                        {
                            LogList.Remove(LogList.First());
                        }
                        if (Globals.DingSet_On == 1)
                        {
                            ///钉钉发送
                            DingSend.MsgSend(
                                Globals.DingSet_Url,
                                Globals.DingSet_SafeCode,
                                read.ModelName + "-" + read.ModelContent);
                        }

                    }
                    catch (Exception ex)
                    {
                        Log logs = new Log();
                        logs.HappenTime = DateTime.Now.ToString("MM-dd HH:mm:ss");
                        logs.HappenModel = read.ModelName;
                        logs.HappenDtal = ex.Message + "-" + read.ModelContent;
                        LogList.Add(logs);
                        LogRead red = new LogRead();
                        red.ModelName = "AddLogCommandImpl";
                        red.ModelContent = logs.HappenDtal;
                        AddLogLocalHostCommandImpl(red);
                    }
                }));
            });
        }

        private Result<string> AddLogLocalHostCommandImpl(LogRead read)
        {
            Result<string> result = new Result<string>()
            {
                Code = 200,
                Message = "请求成功",
                Success = true
            };
            try
            {
                string path = @"log\";
                string readme = "Error" + read.ModelName + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
                string txtpath = path + "/" + readme;//文件存放路径
                DirectoryInfo directoryInfo = new DirectoryInfo(path);
                if (!directoryInfo.Exists)  //判断 文件夹是否存在
                {
                    directoryInfo.Create();
                }
                if (!File.Exists(txtpath))
                {
                    File.Create(txtpath).Close();//判断文件是否存在，创建txt文件后需要close，否则会出现文件占用情况
                }
                StreamWriter sw = new StreamWriter(txtpath, true, System.Text.Encoding.Default);//第一个参数代表路径，第二个参数表示文件是否覆盖还是在原有文件基础上添加，第三个参数代表编码格式
                sw.WriteLine(read.ModelContent);//写入txt文件
                sw.Flush();
                sw.Close();
            }
            catch (Exception ex)
            {
                result.Code = 500;
                result.Message = $"AddLogLocalHostCommandImpl 发生异常：{ex.Message}";
                result.Success = false;
            }
            return result;
        }

        private Result<int> AddJobCommandImpl(Job job)
        {
            Result<int> result = new Result<int>()
            {
                Code = 200,
                Message = "请求成功",
                Success = true
            };
            try
            {
                var service = Locator.Current.GetService<IDBHelperService>();
                using (var db = service.SqlSugarClient(Globals.DbConnect, Globals.DbType))
                {
                    result.Data = db.Insertable(job).ExecuteCommand();
                    SelectJobCommandImpl();
                }
            }
            catch (Exception ex)
            {
                result.Code = 500;
                result.Message = $"AddJobCommandImpl 发生异常：{ex.Message}";
                result.Success = false;
            }
            return result;
        }

        public Result<int>UpdateJobCommandImpl(Job job)
        {
            Result<int> result = new Result<int>()
            {
                Code = 200,
                Message = "请求成功",
                Success = true
            };
            try
            {
                var service = Locator.Current.GetService<IDBHelperService>();
                using (var db = service.SqlSugarClient(Globals.DbConnect, Globals.DbType))
                {
                    result.Data = db.Updateable(job).Where(x => x.JobCode == job.JobCode).ExecuteCommand();
                    SelectJobCommandImpl();
                }
            }
            catch (Exception ex)
            {
                result.Code = 500;
                result.Message = $"UpdateJobCommandImpl 发生异常：{ex.Message}";
                result.Success = false;
            }
            return result;
        }

        public Result<Job> SelectOneJobCommandImpl(string JobCode)
        {
            Result<Job> result = new Result<Job>()
            {
                Code = 200,
                Message = "请求成功",
                Success = true
            };
            try
            {
                var service = Locator.Current.GetService<IDBHelperService>();
                using (var db = service.SqlSugarClient(Globals.DbConnect, Globals.DbType))
                {
                    result.Data = db.Queryable<Job>().Where(x => x.JobCode == JobCode).ToList().FirstOrDefault();
                }
            }
            catch (Exception ex)
            {
                result.Code = 500;
                result.Message = $"SelectOneJobCommandImpl 发生异常：{ex.Message}";
                result.Success = false;
            }
            return result;

        }

        private Result<Setting> GetSetValueCommandImpl(string setName)
        {
            Result<Setting> result = new Result<Setting>()
            {
                Code = 200,
                Message = "请求成功",
                Success = true
            };
            if (SetList.Where(x => x.SetName == setName).ToList() == null)
            {
                result.Code = 500;
                result.Message = $"无此项{setName}";
                result.Success = false;
            }
            else
            {
                result.Data = SetList.Where(x => x.SetName == setName).ToList().FirstOrDefault();
            }
            return result;
        }

        private Result<int> DeleteJobCommandImpl(Job job)
        {
            Result<int> result = new Result<int>()
            {
                Code = 200,
                Message = "请求成功",
                Success = true
            };
            try
            {
                var service = Locator.Current.GetService<IDBHelperService>();
                using (var db = service.SqlSugarClient(Globals.DbConnect, Globals.DbType))
                {
                    result.Data = db.Deleteable<Job>().Where(x => x.JobCode == job.JobCode && x.JobStatus == job.JobStatus).ExecuteCommand();
                    if (result.Data > 0)
                    {
                        JobList.Remove(job);
                    }
                    SelectJobCommandImpl();
                }
            }
            catch (Exception ex)
            {
                result.Code = 500;
                result.Message = $"DeleteJobCommandImpl 发生异常：{ex.Message}";
                result.Success = false;
            }
            return result;
        }

        #region 控件方法


        #endregion
    }
}
